#ifndef Ink_First
#define Ink_First
#ifdef __GNUG__
#pragma interface
#endif

#include "Object.h"

class RGB;
class Ink;
class HSVColor;
class RGBColor;
class InkManager;
class Port;
class OrdCollection;
class HSVColor;

const int
	cMinRGB         = 0,
	cMaxRGB         = 255,
	cOpaque         = cMaxRGB,
	cTransparent    = cMinRGB,
	MaxWord         = 255;      // obsolete

extern InkManager *gInkManager;

extern Ink
	*gInkXor,
	*gInkNone,
	*gInkWhite,
	*gInkRed,
	*gInkGreen,
	*gInkBlue,
	*gInkMagenta,
	*gInkCyan,
	*gInkYellow,
	*gInkViolet,
	*gInkOrange,
	*gInkBlack,
	*gHighlightColor;
	       
// obsolete !!!
extern Ink *ePatXor, *ePatNone, *ePatWhite, *ePatBlack;
extern Ink *ePatGrey12, *ePatGrey25, *ePatGrey40, *ePatGrey50, *ePatGrey60;
extern Ink *ePatGrey75;
extern Ink *ePat00, *ePat01, *ePat02, *ePat03, *ePat04, *ePat05;
extern Ink *ePat06, *ePat07, *ePat08, *ePat09, *ePat10, *ePat11;
extern Ink *ePat12, *ePat13, *ePat14, *ePat15;

enum InkFlags {
	eInkChanged     =   BIT(eObjLast+1),
	eInkLast        =   eObjLast + 1
};

//---- Ink ---------------------------------------------------------------------

class Ink : public Object {
	long int id;
public:
	MetaDef(Ink);
	Ink();
	Ink(long i);

	long GetId()
		{ return id; }
		
	void SetId(long id);
	virtual void SetInk(Port *p);
	bool IsEqual(Object*);
	OStream& PrintOn(OStream&);
	IStream& ReadFrom(IStream&);
	Object *ReadAndMap(IStream&);
};

//---- RGB ---------------------------------------------------------------------

class RGB {
public:
	short red, green, blue;
	short alpha;

public:
	RGB();
	RGB(const RGB &c);
	RGB(const HSVColor &c);
	RGB(float graylevel);
	RGB(short rgb, short a= cMaxRGB);
	RGB(short r, short g, short b, short a= cMaxRGB);

	void SetRGB(short r, short g, short b, short a= cMaxRGB );
	bool IsGrey();
	OStream& PrintOn(OStream&);
	IStream& ReadFrom(IStream&);
	friend OStream& operator<< (OStream &os, RGB &rgb);
	friend IStream& operator>> (IStream &is, RGB &rgb);
	short AsGreyLevel();

	friend bool operator==(const RGB &c1, const RGB &c2);
	friend bool operator!=(const RGB &c1, const RGB &c2);

	friend RGB operator-(const RGB &op1, const RGB &op2);
	friend RGB operator+(const RGB &op1, const RGB &op2);
	friend RGB operator*(const RGB &op1, int v);
	friend RGB operator/(const RGB &op1, int v);

	RGB operator+=(const RGB &op1);

	void Clamp();
};

SimpleMetaDef(RGB);

inline RGB::RGB()
	{ red= green= blue= 0; alpha= cMaxRGB; }
inline RGB::RGB(short rgb, short a)
	{ red= green= blue= rgb; alpha= a; }
inline RGB::RGB(short r, short g, short b, short a)
	{ red= r; green= g; blue= b; alpha= a; }
inline bool RGB::IsGrey()
	{ return red == green && green == blue; }
inline OStream& operator<< (OStream &os, RGB &rgb)
	{ return rgb.PrintOn(os); }
inline IStream& operator>> (IStream &is, RGB &rgb)
	{ return rgb.ReadFrom(is); }
inline bool operator==(const RGB &c1, const RGB &c2)
	{ return (bool) (c1.red == c2.red && c1.green == c2.green
				&& c1.blue == c2.blue && c1.alpha == c2.alpha); }
inline bool operator!=(const RGB &c1, const RGB &c2)
	{ return (bool) (c1.red != c2.red || c1.green != c2.green
				|| c1.blue != c2.blue || c1.alpha != c2.alpha); }
inline RGB operator-(const RGB &op1, const RGB &op2)
	{ return RGB(op1.red-op2.red, op1.green-op2.green, op1.blue-op2.blue); }
inline RGB operator+(const RGB &op1, const RGB &op2)
	{ return RGB(op1.red+op2.red, op1.green+op2.green, op1.blue+op2.blue); }
inline RGB operator*(const RGB &op1, int v)
	{ return RGB(op1.red*v, op1.green*v, op1.blue*v); }
inline RGB operator/(const RGB &op1, int v)
	{ return RGB(op1.red/v, op1.green/v, op1.blue/v); }
inline RGB RGB::operator+=(const RGB &op1)
	{ red+= op1.red; green+= op1.green; blue+= op1.blue; return *this; }
inline void RGB::Clamp() {
	if (red < cMinRGB) red= cMinRGB; else if (red > cMaxRGB) red= cMaxRGB;
	if (green < cMinRGB) green= cMinRGB; else if (green > cMaxRGB) green= cMaxRGB;
	if (blue < cMinRGB) blue= cMinRGB; else if (blue > cMaxRGB) blue= cMaxRGB;
	if (alpha < cMinRGB) alpha= cMinRGB; else if (alpha > cMaxRGB) alpha= cMaxRGB;
	}

//---- HSVColor -------------------------------------------------------------------

class HSVColor {
public:
	short hue, saturation, value;
	short alpha;

public:
	HSVColor()
		{ }
	HSVColor(const HSVColor &c);
	HSVColor(const RGB &c);
	HSVColor(short graylevel, short a= cMaxRGB)
		{ hue= saturation= cMinRGB; value= graylevel; alpha= a; }
	HSVColor(const RGBColor&);
	HSVColor(short h, short s, short v, short a= cMaxRGB)
		{ hue= h; saturation= s; value= v; alpha= a; }
	OStream& PrintOn(OStream &os) const;
	IStream& ReadFrom(IStream &is);
	friend OStream& operator<< (OStream &os, const HSVColor &hsv);
	friend IStream& operator>> (IStream &is, HSVColor &hsv);
};

SimpleMetaDef(HSVColor);

inline OStream& operator<< (OStream &os, const HSVColor &hsv)
	{ return hsv.PrintOn(os); }
inline IStream& operator>> (IStream &is, HSVColor &hsv)
	{ return hsv.ReadFrom(is); }

//---- RGBColor ----------------------------------------------------------------

class RGBColor: public Ink {
friend HSVColor;
	short prec;
	RGB rgb;
public:
	Port *port;

public:
	MetaDef(RGBColor);
	RGBColor();
	RGBColor(RGBColor*);
	RGBColor(const RGB &c, short prec= 0);
	RGBColor(const HSVColor &h, short prec= 0);
	RGBColor(const RGBColor &c);
	RGBColor(short r, short g, short b, short prec= 0);
	RGBColor(short graylevel, short prec= 0);
	RGBColor(float graylevel, short prec= 0);

	short GetRed()
		{ return rgb.red; }
	short GetGreen()
		{ return rgb.green; }
	short GetBlue()
		{ return rgb.blue; }
	short GetPrec()
		{ return prec; }
	RGB *GetRGB()
		{ return &rgb; }
	bool SetHSV(short hue, short sat, short value, short p= 0);
	bool SetRGB(RGB *rgb, short p= 0);
	bool SetRGB(short r, short g, short b, short p= 0);
	bool SetRed(short r)
		{ return SetRGB(r, rgb.green, rgb.blue, prec); }
	bool SetGreen(short g)
		{ return SetRGB(rgb.red, g, rgb.blue, prec); }
	bool SetBlue(short b)
		{ return SetRGB(rgb.red, rgb.green, b, prec); }
	bool SetPrec(short p)
		{ return SetRGB(rgb.red, rgb.green, rgb.blue, p); }
	int AsGreyLevel()
		{ return rgb.AsGreyLevel(); }

	void SetInk(Port *p);
	OStream& PrintOn(OStream&);
	IStream& ReadFrom(IStream&);
	Object *ReadAndMap(IStream&);
};

//---- RGBColorCell ------------------------------------------------------------

class RGBColorCell: public RGBColor {
public:
	MetaDef(RGBColorCell);
	RGBColorCell(int id);
	void SetInk(Port *p);
	OStream& PrintOn(OStream&);
	IStream& ReadFrom(IStream&);
	Object *ReadAndMap(IStream&);
};

//---- InkManager --------------------------------------------------------------

class InkManager : public Object {
public:
	MetaDef(InkManager);
	InkManager();
	virtual ~InkManager();

	friend RGBColor *new_RGBColor(const char *name, short prec= 0);
	friend RGBColor *new_RGBColor(short r, short g, short b, short prec= 0);
	friend RGBColor *new_Grey(float graylevel, short prec= 0);
	friend Ink *new_Ink(const char *name, Ink *dflt);

	RGB *FindRGB(const char *name);
	char *FindName(const RGB &rgb, bool exact= FALSE);
	bool ParseColor(RGB &rgb, const char *c);

	bool Init();        // returns TRUE on error
protected:
	void ReadRgbNames();

private:
	OrdCollection *sharedinks;
	OrdCollection *namedRGBMap;
};

#endif
